package com.csap.framework.validation.factory;

import com.csap.framework.properties.apidoc.ModelType;
import com.csap.framework.util.ObjectUtil;
import com.csap.framework.util.map.CsapMap;
import com.csap.mybatisplus.core.toolkit.ReflectionKit;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.reflect.MethodSignature;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author yangchengfu
 * @description 验证工厂类
 * @dataTime 2021年-01月-22日 20:47:00
 **/
@Slf4j
public class ValidateFactory extends BaseFactory {
    @Getter
    private ConstraintHelper constraintHelper;

    public ValidateFactory(ConstraintHelper constraintHelper) {
        this.constraintHelper = constraintHelper;
    }


    /**
     * 验证参数
     *
     * @param args            参数
     * @param method          方法
     * @param controllerClass 当前类
     * @param paramClass      参数类型
     * @param parameterName   参数名
     */
    public void validation(Object args, MethodSignature method, Class<?> controllerClass, Class<?> paramClass, String parameterName) {
        //TODO 基础验证
        Validate.ValidateField validateField = request(controllerClass, method.getMethod(), paramClass.getSimpleName());
        if (validateField == null) {
            return;
        }
        validateField.validators(args);
        if (validateField.getModelType().equals(ModelType.BASE_DATA)) {
            if (validateField.getChildren().containsKey(parameterName)) {
                validateField.getChildren().get(parameterName).validators(args);
            }
        } else {
            //TODO 级联验证
            validatorsChildren(parameterName, validateField.getChildren(), args, null, (fileName, appendKey, value) -> ReflectionKit.getValidateValue(fileName, appendKey, value));
        }
    }

    /**
     * 验证当前级联业务
     *
     * @param validateField 当前的级联验证信息
     * @param value         验证的数据
     * @param function      验证函数 <<key is fieldName return value is field value
     */
    public Validate.ValidateField validatorsChildren(String parameterName, CsapMap<String, Validate.ValidateField> validateField, Object value, Object childrenValue, BiFunctionValidation<String, List<String>, Object, Object> function) {
        return validateField
                .entrySet()
                .stream()
                .map(e -> validatorsField(parameterName, e, childrenValue != null ? childrenValue : value, function))
                .filter(ObjectUtil::isNotEmpty)
                .filter(i -> i.getMapData().getValue().getChildren().size() > 0)
                .map(e -> validatorsChildren(parameterName, e.getMapData().getValue().getChildren(), e.getValue(), childrenValue, function))
                .filter(ObjectUtil::isNotEmpty)
                .findFirst().orElse(null);
    }

    /**
     * 验证字段
     *
     * @param validateFieldEntry
     * @param value
     * @param function
     * @return
     */
    private StoreData validatorsField(String parameterName, Map.Entry<String, Validate.ValidateField> validateFieldEntry, Object value, BiFunctionValidation<String, List<String>, Object, Object> function) {
        Object values = value;
        if (!ModelType.BASE_DATA.equals(validateFieldEntry.getValue().getModelType()) && values != null && values instanceof Collection) {
            for (Object i : (Collection) values) {
                validatorsChildren(parameterName, CsapMap.<String, Validate.ValidateField>build().add(validateFieldEntry.getKey(), validateFieldEntry.getValue()), i, null, function);
            }
            return null;
        } else {
            if (ModelType.BASE_DATA.equals(validateFieldEntry.getValue().getModelType())) {
                validateFieldEntry.getValue().validators(values);
            } else {
                values = function.apply(validateFieldEntry.getKey(), null, values);
                validateFieldEntry.getValue().validators(values);
            }
        }
        return StoreData.builder()
                .mapData(validateFieldEntry)
                .value(values)
                .build();
    }
}
